package com.taldh.springdata.config;

import com.taldh.springdata.JpaFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.Objects;
import java.util.Set;

public class JpaRegistry implements ResourceLoaderAware , ImportBeanDefinitionRegistrar, EnvironmentAware {

    private final String baseScannerPackages ="com.taldh.springdata.dao";

    private ResourceLoader resourceLoader;
    private Environment environment;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //这个方法实现不符合单一原则，这里只是演示，大家不要学习。
        JpaScanner jpaScanner = new JpaScanner(Collections.emptySet(), registry);
        jpaScanner.setEnvironment(environment);
        jpaScanner.setResourceLoader(resourceLoader);
        Set<BeanDefinition> candidateComponents = jpaScanner.findCandidateComponents(baseScannerPackages);
        candidateComponents.forEach(component -> {
            // 玄机在这里，注册的时候注册进去的是FactoryBean，而不是直接扫描到的Bean。
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(JpaFactoryBean.class.getName());
            Class<?> tClazz = null;
            try {
                tClazz = Class.forName(component.getBeanClassName());
            } catch (ClassNotFoundException e) {
                // 这里不会出现异常，因为class是经过扫描出来的。所以忽略这个异常即可。
            }
            builder.addConstructorArgValue(tClazz);
            AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
            registry.registerBeanDefinition(StringUtils.uncapitalize(Objects.requireNonNull(tClazz).getSimpleName()), beanDefinition);
        });
    }

}
